const path = require("path");
const fs = require("fs");
const mime = require("mime-types");
const { v4 } = require("uuid");
const AppConfig = require("$config/app.config");
const { Result } = require("@/libs/result");
const fileUtil = require("@/utils/file.util");
const AesSecurity = require("@/security/aes.security");
const fileModel = require("./file.model");
const redisClient = require("@/redis/redis-client");
const redisKeysConstant = require("@/constants/redis-keys.constant");
const fileBusinessService = require("@/common/file-business.service");
const { commonService } = require("../../common/file-business.service");
const aesSecurity = new AesSecurity();

/**
 * 附件Service
 */
class FileService {
	/**
	 * 上传文件
	 * @param {*} file
	 * @returns
	 */
	async upload(file) {
		try {
            const path = file.path.replace(/\\/g, "/");
			const [error, result] = await fileModel.uploadFile({
				name: file.filename,
                path: path.replace(AppConfig.FILE_UPLOAD_PATH, '/'),
				suffix: file.filename.split(".").pop(),
				size: file.size,
                original_name: file.originalname,
                storage_type: 1
			});
            if (error) {
                return Result.Failed('上传失败');
			}
            this.setMD5Hash({ fileId: result.id, filePath: path }); // 异步设置文件hash
            if (result) {
                delete result.path;
            }
            return Result.Success(result);
		} catch (error) {
			console.log(error);
			return Result.Failed('上传失败');
		}
	}

	/**
	 * 绑定业务
	 * @param {*} bizId 业务id
	 * @param {} files 文件id列表
	 * @returns
	 */
	async bindBizFile({ files, business_id, business_type, file_category, extra_data, file_purpose }) {
        try {
            if (!files || !business_id) {
                return Result.Failed("绑定文件失败");
            }
            const [error, result] = await fileModel.bidBizFile({
                files: files,
                business_id: business_id,
                business_type: business_type || 'unknown',
                file_category: file_category,
                extra_data: extra_data,
                file_purpose: file_purpose,
                result: true
            });

            if (error) {
                return Result.Failed("绑定文件失败");
            }

			// await fileModel.setFileBindBusiness(files); // 修改绑定状态
            // await fileBusinessService.syncFamilyGroupStoreSize(gid); // 同步家庭组存储大小
			return Result.Success(result);
		} catch (error) {
			return Result.Failed("绑定文件失败");
		}
	}

	/**
	 * 查询业务的文件列表
	 * @param {*} param0
	 * @returns
	 */
	async queryFileByBiz(bizId) {
        try {
            const files = await fileBusinessService.getBusinessFiles(bizId);
            return Result.Success(files);
		} catch (error) {
			return Result.Failed(error);
		}
	}

	/**
	 * 删除文件
	 * @param {*} param0
	 * @returns
	 */
	async deleteFile({ file_id }) {
		try {
			const [error] = await fileModel.deleteFile({ id: file_id });
            if (error) {
                return Result.Failed('文件删除失败');
            }
            return Result.Success();
		} catch (error) {
			return Result.Failed('文件删除失败');
		}
	}

	/**
	 * 设置md5 hash
	 * @param {*} param0
	 */
	async setMD5Hash({ fileId, filePath }) {
		const md5Hash = await fileUtil.getFileMD5(filePath);
		if (md5Hash === null) {
			console.log(`文件${fileId}MD5 hash获取失败！`);
			return;
		}
		console.log("MD5: " + md5Hash.toUpperCase());
		fileModel.setFileMD5Hash({ id: fileId, hash: md5Hash.toUpperCase() }); // 同步到库
	}

	/**
	 * 文件预览
	 * @param {*} fileName
	 * @param {*} query
	 * @returns
	 */
	async previewFile(ctx, fileName, code) {
		const errorResult = message => {
			return { error: true, message: encodeURIComponent(message) };
		};
		try {
			if (!fileName || !code) {
				return errorResult("预览失败");
			}
			code = decodeURIComponent(code);
			const redisKey = `file:preview:${code}`;
			let redisFile = await redisClient.get(redisKey); // 在redis中查询文件信息
			if (!redisFile) {
				return errorResult("参数无效");
			}
			if (fileName !== redisFile.name) {
				return errorResult("参数无效");
			}
			// 验证有效期
			const cacheFile = JSON.parse(aesSecurity.decrypt(redisFile.code));
			if (Date.now() > cacheFile.ext) {
				await fileBusinessService.deletePreviewExpiredFile(redisKey); // 删除redis中缓存数据
				return errorResult("文件已过期");
			}
            const filePath = `${cacheFile.path}`;
            let file = null;
			try {
                file = fs.readFileSync(filePath);
            } catch (error) {
                return errorResult("文件资源不存在");
            }
			return {
				type: mime.lookup(filePath),
				body: file
			};
		} catch (error) {
			console.log("文件预览error:", error);
			return errorResult(error);
		}
	}
}

module.exports = {
	fileService: new FileService()
};
